package com.netty.tcp.task;

import com.alibaba.fastjson.JSONObject;
import com.netty.tcp.ew.domain.*;
import com.netty.tcp.ew.mapper.*;
import com.netty.tcp.nettyService.NettyServerHandler;
import com.netty.tcp.redis.RedisCache;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelId;
import io.netty.channel.group.ChannelGroup;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Set;
import com.netty.tcp.task.SendMessage;

/**
 * 定时任务发布消息队列
 */
@Configuration
@EnableScheduling
public class RedisPubTask {
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private Integer port;
    @Value("${spring.redis.password}")
    private String password;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ControlCommandLogSystemMapper controlCommandLogSystemMapper;

    @Autowired
    private DeviceControlMapper deviceControlMapper;

    @Autowired
    private BaseAccountMapper baseAccountMapper;

    @Autowired
    private FinancialStatementMapper financialStatementMapper;

    @Autowired
    private BasePriceMapper basePriceMapper;

    @Autowired
    private SendMessage sendMessage;

    private JedisPool jedisPool =  new JedisPool(new JedisPoolConfig(), "localhost", 13521,0,"wujunlei");
    private Jedis jedis = jedisPool.getResource();



    /**
     * 今日任务，在00：01：00开始执行一次
     */
    @Scheduled(cron = "0 18 19 ? * *")
    private void todaytask() throws ParseException {
        //组织今天的任务
        Date today = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat(("yyyy-MM-dd"));
        SimpleDateFormat timeFormat = new SimpleDateFormat(("HH:mm:ss"));
//        System.out.println("今天的日期是："+dateFormat.format(today));
//        System.out.println("当前的时间是："+System.currentTimeMillis()+"时间格式是："+timeFormat.format(System.currentTimeMillis()));
        BasePrice basePrice = new BasePrice();
        List<BasePrice> basePriceList = basePriceMapper.selectBasePriceList(basePrice);
        for (BasePrice b:basePriceList) {
            System.out.println("任务:"+timeFormat.format(b.getPriceTime())+"距离现在还有："+(b.getPriceTime().getTime()-(timeFormat.parse(timeFormat.format(System.currentTimeMillis()))).getTime()));
            JSONObject json = new JSONObject();
            json.put("priceId",b.getPriceId());
            json.put("companyId",b.getCompanyId());
            jedis.zadd("todaytask",System.currentTimeMillis()+(b.getPriceTime().getTime()-(timeFormat.parse(timeFormat.format(System.currentTimeMillis()))).getTime()), json.toString());
            System.out.println("今日任务已生成！");

        }
    }
    /**
     * 今日任务出列演示
     */
    @Scheduled(fixedRate=1000)
    private void todaytaskdo(){
        Set<String> values = jedis.zrangeByScore("todaytask", 0, System.currentTimeMillis(), 0, 1);
        if(!values.isEmpty()){
            String s = values.iterator().next();
            JSONObject jsonObject = JSONObject.parseObject(s);
            Integer priceId = (Integer) jsonObject.get("priceId");
            Integer companyId =(Integer) jsonObject.get("companyId");
            DeviceControl d = new DeviceControl();
            d.setDevicePriceId(priceId);
//            d.setCompanyId(companyId);
            List<DeviceControl> deviceControlList = deviceControlMapper.selectDeviceControlList(d);
            for (DeviceControl D: deviceControlList) {
                //将任务添加到队列
                System.out.println("采集器IMEI："+D.getIotImei());
                System.out.println("设备地址："+D.getDeviceAddress());
                System.out.println("协议："+D.getDeviceProtocl());
                System.out.println(sendMessage.instruction(D.getIotImei(),D.getDeviceAddress(),0,D.getDeviceProtocl()));
            }
            System.out.println(s);
            jedis.zrem("todaytask", s);


        }
    }


    /**
     * 出列扫行
     */
    @Scheduled(fixedRate=900)
    private void configureTasks() {
        String message = jedis.lpop("queueName");//blpop阻塞式左出队 ，brpop阻塞式右出队
        if(message != null && message != ""){
            JSONObject jsonObject = JSONObject.parseObject(message);
            String iot_imei = (String) jsonObject.get("iot_imei");
            Integer trytimes = (Integer) jsonObject.get("trytimes");
            String content = StringUtils.deleteWhitespace((String) jsonObject.get("content"));

            //以下是业务操作
            System.out.println("业务处理： " + jsonObject);
            ChannelId channelId = redisCache.getCacheObject(iot_imei);
            if(channelId!=null){
                ByteBuf bufff = Unpooled.buffer();//netty需要用ByteBuf传输
                bufff.writeBytes(hexString2Bytes(content.trim()));//对接需要16进制
                ChannelGroup channelGroup = NettyServerHandler.channelGroup;
                Channel channel = channelGroup.find(channelId);
                if(channel !=null && channel.isActive()){
                    channelGroup.writeAndFlush(bufff);
                }

            }else{
                //任务重回队列
                if(trytimes > 0){
                    System.out.println("目标不在线，正在重试");
                    jsonObject.put("trytimes",trytimes-1);//重试次数减一
                    jedis.rpush("queueName",jsonObject.toString());//rpush右入队，lpush左入队
                }

            }
        }
    }

    /**
     * 延时队列出列
     */
    @Scheduled(fixedRate=100)
    private void consumdelayTasks() throws ParseException {
//        todaytask();
        //处理延时队列任务
        Set<String> values = jedis.zrangeByScore("delaytask", 0, System.currentTimeMillis(), 0, 1);
        if(!values.isEmpty()){
            String s = values.iterator().next();
            JSONObject jsonObject = JSONObject.parseObject(s);
            String iot_imei = (String) jsonObject.get("iot_imei");
            String content =(String) jsonObject.get("content");

            //以下是业务操作
            Date day = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat(("yyyy-MM-dd HH:mm:ss"));
            SimpleDateFormat sdf_time = new SimpleDateFormat(("HH:mm:ss"));

            System.out.println("业务处理：处理时间： "+day.getTime() +"加入时间：" + (sdf_time.parse(content).getTime()/1000+28800));
            jedis.zrem("delaytask", s);
            ChannelId channelId = redisCache.getCacheObject(iot_imei);
//            if(channelId!=null){
//                ByteBuf bufff = Unpooled.buffer();//netty需要用ByteBuf传输
//                bufff.writeBytes(hexString2Bytes(content.trim()));//对接需要16进制
//                ChannelGroup channelGroup = NettyServerHandler.channelGroup;
//                Channel channel = channelGroup.find(channelId);
//                if(channel !=null && channel.isActive()){
//                    channelGroup.writeAndFlush(bufff);
//                }
//            }
        }

    }

    /**
     * 出列扫行接收数据解析
     */
    @Scheduled(fixedRate=100)
    private void receiveTasks() {
        String  result = jedis.lpop("receiveMessage");//blpop阻塞式左出队 ，brpop阻塞式右出队
        if(result != null && result != ""){
            JSONObject jsonObject = JSONObject.parseObject(result);
            String sourceIot = (String) jsonObject.get("sourceIot");
            String message =(String) jsonObject.get("message");
            //Todo 解析数据
            String typeCode = message.substring(16,18);
            switch (typeCode){
               case "91" ://抄读
                   if(message.length()>36){
                       System.out.println("设备地址："+translateAddress(message.substring(2,14)));
                       System.out.println("阀控状态："+message.substring(44,46)+ ((message.substring(44,46).equals("4D")) ? "拉闸" : "合闸"));
                       System.out.println("表显电量："+translateNumber(message.substring(28,36)));
                       System.out.println("表显余额："+translateNumber(message.substring(36,44)));
                       System.out.println("来源IOT："+sourceIot);
                       //写解析日志
                       ControlCommandLogSystem controlCommandLogSystem = new ControlCommandLogSystem();
                       controlCommandLogSystem.setCommandType("抄表");
                       controlCommandLogSystem.setCommandTargetdevice(translateAddress(message.substring(2,14)));
                       controlCommandLogSystem.setCommandContent(message);
                       controlCommandLogSystem.setCommandKeyvalue(translateNumber(message.substring(28,36)).toString());
                       controlCommandLogSystemMapper.insertControlCommandLogSystem(controlCommandLogSystem);

                       //查找设备信息，包括计费方式，计费单价，户号等信息
                       DeviceControl deviceControl = deviceControlMapper.selectDeviceControlByDeviceAddress(translateAddress(message.substring(2,14)));
                       BaseAccount baseAccount = baseAccountMapper.selectBaseAccountByAccountId(deviceControl.getDeviceAccountId());
                       System.out.println("目标IOT："+deviceControl.getIotImei());
                       System.out.println("原读数："+deviceControl.getDeviceRegistrationCount());
                       System.out.println("新读数："+ translateNumber(message.substring(28,36)));
                       System.out.println("用电量:"+(translateNumber(message.substring(28,36)).doubleValue()-deviceControl.getDeviceRegistrationCount().doubleValue()));
                       System.out.println("电价："+deviceControl.getPriceNumber());
                       System.out.println("户号："+deviceControl.getDeviceAccountId());

                       //结算数据做准备
                       FinancialStatement statement = new FinancialStatement();
                       statement.setStatementAccountId(deviceControl.getDeviceAccountId());
                       statement.setStatementDeviceId(deviceControl.getDeviceId());
                       statement.setStatementCost(BigDecimal.valueOf(deviceControl.getPriceNumber().doubleValue()*(translateNumber(message.substring(28,36)).doubleValue()-deviceControl.getDeviceRegistrationCount().doubleValue())));
                       statement.setCompanyId(deviceControl.getCompanyId());
                       statement.setStatementBefore(baseAccount.getAccountBalance());
                       statement.setStatementAfter(BigDecimal.valueOf(baseAccount.getAccountBalance().doubleValue()-deviceControl.getPriceNumber().doubleValue()*(translateNumber(message.substring(28,36)).doubleValue()-deviceControl.getDeviceRegistrationCount().doubleValue())));

                       baseAccountMapper.updateBaseAccountReadout(deviceControl.getPriceNumber().doubleValue()*((translateNumber(message.substring(28,36)).doubleValue()-deviceControl.getDeviceRegistrationCount().doubleValue())),deviceControl.getDeviceAccountId());
                       financialStatementMapper.insertFinancialStatement(statement);

                       


                       //更新设备状态，拉合闸，是否在线，并抄下最近抄读数
                       DeviceControl deviceControl1 = new DeviceControl();
                       deviceControl1.setDeviceAddress(translateAddress(message.substring(2,14)));//设备地址
                       deviceControl1.setDeviceOnOffStatus((message.substring(44,46).equals("4D")) ? "0" : "1");//拉合闸
                       deviceControl1.setDeviceRegistrationCount(translateNumber(message.substring(28,36)));
                       deviceControl1.setDeviceStatus("0");//在线
                       deviceControlMapper.updateDeviceControlByDeviceAddress(deviceControl1);

                   }
                   if(message.length()<=36){
                       System.out.println("设备地址："+translateAddress(message.substring(2,14)));
                   }
                   break;
               case "9C" ://拉合闸
                   System.out.println("设备地址："+translateAddress(message.substring(2,14)));
                   System.out.println("阀控状态："+message.substring(20,22)+ ((message.substring(20,22).equals("4D")) ? "拉闸" : "合闸"));
                   ControlCommandLogSystem controlCommandLogSystem = new ControlCommandLogSystem();
                   controlCommandLogSystem.setCommandType(((message.substring(20,22).equals("4D")) ? "拉闸" : "合闸"));
                   controlCommandLogSystem.setCommandTargetdevice(translateAddress(message.substring(2,14)));
                   controlCommandLogSystem.setCommandContent(message);
                   controlCommandLogSystem.setCommandKeyvalue(((message.substring(20,22).equals("4D")) ? "拉闸" : "合闸"));
                   controlCommandLogSystemMapper.insertControlCommandLogSystem(controlCommandLogSystem);

                   DeviceControl deviceControl = new DeviceControl();
                   deviceControl.setDeviceAddress(translateAddress(message.substring(2,14)));
                   deviceControl.setDeviceOnOffStatus((message.substring(20,22).equals("4D")) ? "0" : "1");
                   deviceControl.setDeviceStatus("0");//在线
                   deviceControlMapper.updateDeviceControlByDeviceAddress(deviceControl);
                   break;
               case "9A" ://清零
                   System.out.println("设备地址："+translateAddress(message.substring(2,14)));

                   break;
               default:
                   System.out.println("接收数据："+message );
                   break;
           }
        }

    }

//    /**
//     * 入队列示例
//     */
//    @Scheduled(fixedRate=1000)
//    private void adddemo() {
//        Date day = new Date();
//        SimpleDateFormat sdf = new SimpleDateFormat(("yyyy-MM-dd HH:mm:ss"));
//        JSONObject json = new JSONObject();
//        json.put("iot_imei","864452066332491");
//        json.put("content", sdf.format(day).toString());
//        JedisPool jedisPool = new JedisPool(new JedisPoolConfig(), host, port,0,password);
//        Jedis jedis1 =  jedisPool.getResource();
//        for(Integer i = 0;i<200;i++){
////            jedis1.rpush("queueName",json.toString());//rpush右入队，lpush左入队
//        }
////        jedis1.rpush("queueName",json.toString());//rpush右入队，lpush左入队
//    }

    /**
     * 入队延时队列示例
     */
    @Scheduled(fixedRate=5000)
    private void delaytaskdemo() {
        Date day = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat(("yyyy-MM-dd HH:mm:ss"));
        JSONObject json = new JSONObject();
        json.put("iot_imei","864452066332492");
        json.put("content","09:00:00");
        JedisPool jedisPool = new JedisPool(new JedisPoolConfig(), host, port,0,password);
        Jedis jedis1 =  jedisPool.getResource();
//        jedis1.zadd("delaytask",System.currentTimeMillis() + 1000, json.toString());

    }

    public byte[] hexString2Bytes(String src) {
        int l = src.length() / 2;
        byte[] ret = new byte[l];
        for (int i = 0; i < l; i++) {
            ret[i] = (byte) Integer.valueOf(src.substring(i * 2, i * 2 + 2), 16).byteValue();
        }
        return ret;
    }

    private String translateAddress(String address){
        int l = address.length() / 2;
        String newAddressss = "";
        for (int i = l; i >0; i--) {
            newAddressss = newAddressss + address.substring((i-1) * 2, (i-1) * 2 + 2);
        }
        return newAddressss.trim();
    }

    private Double translateNumber(String number){
        int l = number.length() / 2;
        String newNumber = "";
        for (int i = l; i >0; i--) {
            newNumber = newNumber + StringUtils.leftPad(Integer.toHexString(Integer.parseInt(number.substring((i-1) * 2, (i-1) * 2 + 2),16)-0X33),4,'0').substring(2,4);
        }
        return Double.parseDouble(String.format("%.2f",(Double.parseDouble(newNumber.trim())/100)));
    }
}
